package com.dream.xcarrecorder.rec;

import android.content.Context;
import android.graphics.Bitmap;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Environment;
import android.util.Log;
import android.util.Size;
import android.view.Surface;

import com.dream.libxrec.camera.CameraPreviewHelper;
import com.dream.libxrec.camera.ICamera;
import com.dream.libxrec.encode.audio.IAudioEncoderListener;
import com.dream.libxrec.encode.video.H265Encoder;
import com.dream.libxrec.encode.video.IVideoEncoder;
import com.dream.libxrec.encode.video.IVideoEncoderListener;
import com.dream.libxrec.rec.Mp4MediaMuxer;
import com.dream.libxrec.utils.ImageUtils;
import com.dream.libxrec.utils.OsdHelper;
import com.luoye.bzyuvlib.BZYUVUtil;
import java.io.File;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;

/**
 * 实际应用场景中，摄像头的相关处理包括：录像（录音）、拍照、预览、推流
 *
 *涉及编码器的功能为：录像、主码流推流、子码流推流，这三者最基础的区别是码率不同，甚至可能帧率，分辨率也不同，所以需要根据实际情况选择合适的编码器，大部分情况下，需要创建多个编码器
 *
 */
public class CameraHelper{

    private Context mContext;
    private ICamera mCamera;
    private IVideoEncoder mVideoEncoder;
    private final OsdHelper mOsdHelper = new OsdHelper(5,5);
    private CameraPreviewHelper mPreviewHelper = null;//预览工具类
    private final AudioHelper mAudioHelper =
            AudioHelper.getInstance();

    private final String TAG = "CameraHelper";
    private MediaFormat mAudioFormat,mVideoFormat;
    private final SimpleDateFormat mSDF = new SimpleDateFormat(
            "HHmmss",Locale.CANADA);
    private final SimpleDateFormat mSDF2 = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss", Locale.CANADA);

    private final Mp4MediaMuxer mMp4MediaMuxer = new Mp4MediaMuxer();
    private final ArrayList<ITakePhotoListener> mTakePhotoListenerList =
            new ArrayList<>();
    private int mScaleWidth = -1;
    private int mScaleHeight = -1;

    private byte[] nv12 = null;
    private byte[] nv21 = null;

    private byte[] mScaleI420 = null;

    private final ICamera.ImageAvailableListener mImageAvailableListener = new ICamera.ImageAvailableListener() {
        @Override
        public void onImageAvailable(String channel, byte[] data,
                                     int type, int width,
                                     int height) {

            if ((mScaleHeight > 0&&mScaleWidth > 0)&&
                    (mScaleHeight != height
                    ||mScaleWidth != width)){
                if (mScaleI420 == null){
                    mScaleI420 = new byte[mScaleWidth*mScaleHeight*3/2];
                }

                int ret = BZYUVUtil.zoomYUV420(data, mScaleI420,width,height,288,352);

                if (ret != 0){
                    Log.i("TAG","缩放失败！"+ret);
                    return;
                }

                data = mScaleI420;
                width = mScaleWidth;
                height = mScaleHeight;
            }

            mOsdHelper.addYuvOsdText(data,width,height,getOsd(),20,
                    20);

            if (mPreviewHelper != null){
                mPreviewHelper.draw(data,false,0);
            }

            //NV21
            if (!mTakePhotoListenerList.isEmpty()){
                if (nv21 == null){
                    nv21 = new byte[data.length];
                }
                BZYUVUtil.yuvI420ToNV21(data,nv21,width,height);
                takePicture(nv21,width,height);
            }

            //NV12
            if (nv12 == null){
                nv12 = new byte[data.length];
            }

            BZYUVUtil.yuvI420ToNV12(data,nv12,width,height);
//            Log.i("TAG","nv12 size:"+nv12.length+"encoder:"+mVideoEncoder);
            if (mVideoEncoder != null){
                mVideoEncoder.encode(nv12,0,data.length);
            }

        }
    };



    private final IVideoEncoderListener mVideoEncoderListener =
            new IVideoEncoderListener() {

        @Override
        public void onFormat(MediaFormat format) {
            mVideoFormat = format;
            startMuxer();
        }

        @Override
        public void onFrame(ByteBuffer buffer, MediaCodec.BufferInfo info) {
            mMp4MediaMuxer.writeVideoFrame(buffer,info);
        }

        @Override
        public void onFrame(boolean isIFrame, byte[] buffer
                , int size, long pts) {}
    };

    private final IAudioEncoderListener mAudioEncoderListener =
            new IAudioEncoderListener() {
        @Override
        public void onFormat(MediaFormat format) {
            mAudioFormat = format;
            startMuxer();
        }

        @Override
        public void onFrame(ByteBuffer buffer,
                            MediaCodec.BufferInfo info) {
            mMp4MediaMuxer.writeAudioFrame(buffer,info);
        }

        @Override
        public void onFrame(byte[] buffer, int size, long pts) {}
    };

    public void init(Context ct,ICamera c){
        this.mContext = ct;
        mCamera = c;
        mCamera.addListener(mImageAvailableListener);
//        mVideoEncoder = new H264Encoder();//H264编码
        mVideoEncoder = new H265Encoder();//H265编码

        Size s = c.getSize();
        mVideoEncoder.init(ct,s.getWidth(),s.getHeight(),true,2*1024*1024);
        mVideoEncoder.addIEncoderListener(mVideoEncoderListener);
        mAudioHelper.addListener(mAudioEncoderListener);
    }

    public void init(Context ct,ICamera c,int scaleHeight,int scaleWidth){
        this.mContext = ct;
        mCamera = c;
        mCamera.addListener(mImageAvailableListener);
        
//        mVideoEncoder = new H264Encoder();//H264编码
        mVideoEncoder = new H265Encoder();
        
        if (scaleHeight > 0&&scaleWidth > 0){
            this.mScaleHeight = scaleHeight;
            this.mScaleWidth = scaleWidth;
            mOsdHelper.setLevelByImageSize(new Size(mScaleWidth,mScaleHeight));
            mVideoEncoder.init(ct,mScaleWidth,mScaleHeight,true,2*scaleWidth*scaleHeight);
        }else{
            Size s = c.getSize();//摄像头的宽高
            mOsdHelper.setLevelByImageSize(s);
            mVideoEncoder.init(ct,s.getWidth(),s.getHeight(),true,2*s.getWidth()*s.getHeight());
        }

        mVideoEncoder.addIEncoderListener(mVideoEncoderListener);
        mAudioHelper.addListener(mAudioEncoderListener);
    }

    private void startMuxer(){
        if (mAudioFormat != null&&mVideoFormat!= null){
            mMp4MediaMuxer.start(mAudioFormat,mVideoFormat,  new Mp4MediaMuxer.IMuxerBuilder() {
                @Override
                public String getFilePath() {
                   return  mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES)+ File.separator+"rec_"+mCamera.getChannel()+"_"+ mSDF.format(new Date())+".mp4";
                }

                @Override
                public boolean isEndFile(long recTime) {
                    //单个视频时长1分钟
                    return recTime > 1000*1000*60;
                }
            });
        }
    }

    /**
     *
     * @return 水印内容
     */
    private String getOsd(){
        return mSDF2.format(new Date());
    }

    public synchronized boolean isRun() {
        if (mCamera == null||mVideoEncoder == null){
            return false;
        }

        return mCamera.isRun()&&mVideoEncoder.isRun();
    }

    public void start() {
        if (mCamera != null&&!mCamera.isRun()){
            mCamera.start();
        }

        if (mVideoEncoder != null&&!mVideoEncoder.isRun()){
            mVideoEncoder.start();
        }
    }

    public void stop() {
        if (mCamera != null){
            mCamera.stop();
        }
        mCamera = null;

        if (mVideoEncoder!= null){
            mVideoEncoder.stop();
        }

        try {
            mMp4MediaMuxer.stop();
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    public Size getSize(){
        if (mCamera == null){
            return null;
        }

        return mCamera.getSize();
    }

    public void setPreview(Surface surface) {
        if (surface != null){
            mPreviewHelper = new CameraPreviewHelper();
            if (mCamera != null){
                if (mScaleWidth == -1||mScaleHeight == -1){
                    Size s = mCamera.getSize();
                    mPreviewHelper.setPreview(surface,s.getWidth(),s.getHeight(),true);
                }else{
                    mPreviewHelper.setPreview(surface,mScaleWidth,mScaleHeight,true);
                }
            }
        }else{
            if (mPreviewHelper!= null){
                mPreviewHelper.setPreview(null,0,0,true);
            }
        }
    }

    public void takePicture(CameraHelper.ITakePhotoListener listener) {
        mTakePhotoListenerList.add(listener);
    }

    private void takePicture(byte[] nv21, int width, int height) {
        ITakePhotoListener listener = mTakePhotoListenerList.get(0);
        mTakePhotoListenerList.remove(listener);
        Bitmap bitmap = ImageUtils.nv21toBitmap(nv21,width,height,
                100);
        listener.onTakePhoto(mCamera.getChannel(),bitmap);
    }

    public interface ITakePhotoListener{
        void onTakePhoto(String channel, Bitmap bitmap);
    }
}
